package com.tfkj.service;

import com.tfkj.vo.InputStreamDTO;
import com.tfkj.vo.QuestionPDFVO;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.apache.pdfbox.text.PDFTextStripper;
import org.apache.pdfbox.text.TextPosition;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO;
import java.util.LinkedList;
import java.util.Queue;

public class PDFParserUtil {

    public static List<QuestionPDFVO> parsePDF(InputStream pdfStream, double offset) throws IOException {
        List<QuestionPDFVO> result = new ArrayList<>();
        try (PDDocument document = PDDocument.load(pdfStream)) {
            // 获取第一页的黑色块坐标
            double[] blockCoords = getFirstPageBlockCoordinates(document);
            double blockX = blockCoords[0];
            double blockY = blockCoords[1];
            System.out.println("blockX:"+ blockX);
            System.out.println("blockY:"+ blockY);
            int globalQuestionNumber = 1;
            String ctype = "";
            for (int pageIndex = 0; pageIndex < document.getNumberOfPages(); pageIndex++) {
                PDPage page = document.getPage(pageIndex);
                PDRectangle mediaBox = page.getMediaBox();
                double pageWidth = mediaBox.getWidth();
                double pageHeight = mediaBox.getHeight();
                List<TextPosition> positions = getTextPositions(document, pageIndex);
                List<QuestionPosition> questions = findQuestions(positions, offset, globalQuestionNumber, pageHeight, ctype);

                if (!questions.isEmpty()) {
                    if (questions.get(questions.size() - 1).questionNumber != -1) {
                        globalQuestionNumber = questions.get(questions.size() - 1).questionNumber + 1;
                    } else {
                        globalQuestionNumber = questions.get(questions.size() - 2).questionNumber + 1;
                    }
                }

                if (!questions.isEmpty()) {
                    ctype = questions.get(questions.size() - 1).questionModel;
                }
            // 检查页面尺寸
                PDRectangle cropBox = page.getCropBox();
                double widthInch = cropBox.getWidth() / 72F;
                double heightInch = cropBox.getHeight() / 72F;
                double width = widthInch * 300;
                double height = heightInch * 300;
                double rateX = width / pageWidth;
                double rateY = height / pageHeight;

                System.out.println("Rendered dimensions: " + width + "x" + height);

                // 使用最新PDFBox渲染
                PDFRenderer renderer = new PDFRenderer(document);
                BufferedImage pageImage = renderer.renderImageWithDPI(pageIndex, 300);
                for (QuestionPosition qp : questions) {
                    if (!qp.flag) continue;
                    if (qp.endY == 0) qp.endY = pageHeight - 45;
                    QuestionPDFVO vo = new QuestionPDFVO();
                    // 坐标调整：减去黑色块坐标
                    vo.setX1(0);
                    vo.setY1(qp.startY);
                    vo.setX2(pageWidth);
                    vo.setY2(qp.endY);
                    vo.setX3(adjustCoordinate(qp.rX - 22, blockX));
                    vo.setY3(adjustCoordinate(qp.rY - 3, blockY));
                    vo.setX4(adjustCoordinate(qp.rX + 50, blockX));
                    vo.setY4(adjustCoordinate(qp.rY + 23, blockY));

                    // 其他属性设置保持不变
                    vo.setQuestionModel(qp.questionModel);
                    vo.setQuestionNumber(qp.questionNumber);
                    vo.setPageNumber(pageIndex + 1);
                    vo.setPageWidth(pageWidth);
                    vo.setPageHeight(pageHeight);
                    vo.setScore(qp.x);

                    // 图片截取逻辑保持不变
                    BufferedImage subImage = pageImage.getSubimage(
                            0, (int) (Math.ceil(qp.startY-10) * rateY),
                            (int) (pageWidth * rateX) , (int) (Math.floor(qp.endY - qp.startY) * rateY)
                    );
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    ImageIO.write(subImage, "png", baos);
                    InputStreamDTO dto = new InputStreamDTO();
                    dto.setLength(baos.size());
                    dto.setInputStream(new ByteArrayInputStream(baos.toByteArray()));
                    vo.setImage(dto);
                    result.add(vo);
                }

            }
        }
        return result;
    }

    // 获取页面所有文本位置
    private static List<TextPosition> getTextPositions(PDDocument doc, int pageIndex) throws IOException {
        List<TextPosition> positions = new ArrayList<>();
        PDFTextStripper stripper = new PDFTextStripper() {
            @Override
            protected void writeString(String text, List<TextPosition> textPositions) {
                positions.addAll(textPositions);
            }
        };
        stripper.setSortByPosition(true);
        stripper.setStartPage(pageIndex + 1);
        stripper.setEndPage(pageIndex + 1);
        stripper.getText(doc);
        return positions;
    }
    // 新增方法：坐标调整
    private static double adjustCoordinate(double original, double blockCoord) {
        return original - blockCoord;
    }
    // 改进版黑色方块坐标检测
    private static class Point {
        final int x;
        final int y;

        Point(int x, int y) {
            this.x = x;
            this.y = y;
        }
    }

    private static class Rectangle {
        final int x;
        final int y;
        final int width;
        final int height;

        Rectangle(int x, int y, int width, int height) {
            this.x = x;
            this.y = y;
            this.width = width;
            this.height = height;
        }
    }

    private static double[] getFirstPageBlockCoordinates(PDDocument document) throws IOException {
        PDPage firstPage = document.getPage(0);
        PDFRenderer renderer = new PDFRenderer(document);
        // 高分辨率渲染（300 DPI）
        BufferedImage image = renderer.renderImageWithDPI(0, 300);
        int imgWidth = image.getWidth();
        int imgHeight = image.getHeight();
        PDRectangle mediaBox = firstPage.getMediaBox();
        float pageWidth = mediaBox.getWidth();
        float pageHeight = mediaBox.getHeight();

        // 1. 收集所有黑色像素
        List<Point> blackPixels = new ArrayList<>();
        for (int y = 0; y < imgHeight; y++) {
            for (int x = 0; x < imgWidth; x++) {
                int rgb = image.getRGB(x, y);
                int r = (rgb >> 16) & 0xFF;
                int g = (rgb >> 8) & 0xFF;
                int b = rgb & 0xFF;
                if (r <= 30 && g <= 30 && b <= 30) {
                    blackPixels.add(new Point(x, y));
                }
            }
        }

        if (blackPixels.isEmpty()) {
            throw new IOException("未找到黑色像素区域");
        }

        // 2. 连通区域分析
        boolean[][] visited = new boolean[imgHeight][imgWidth];
        List<List<Point>> regions = new ArrayList<>();

        for (Point p : blackPixels) {
            if (!visited[p.y][p.x]) {
                List<Point> region = new ArrayList<>();
                Queue<Point> queue = new LinkedList<>();
                queue.add(p);
                visited[p.y][p.x] = true;
                region.add(p);

                while (!queue.isEmpty()) {
                    Point current = queue.poll();
                    // 8邻域检测
                    for (int dx = -1; dx <= 1; dx++) {
                        for (int dy = -1; dy <= 1; dy++) {
                            int nx = current.x + dx;
                            int ny = current.y + dy;
                            if (nx >= 0 && nx < imgWidth && ny >= 0 && ny < imgHeight
                                    && !visited[ny][nx]
                                    && isBlackPixel(image, nx, ny)) {
                                visited[ny][nx] = true;
                                queue.add(new Point(nx, ny));
                                region.add(new Point(nx, ny));
                            }
                        }
                    }
                }
                regions.add(region);
            }
        }

        // 3. 过滤小面积区域（面积>=100像素）
        List<Rectangle> candidates = new ArrayList<>();
        int searchWidth = imgWidth / 8;
        int searchHeight = imgHeight / 8;

        for (List<Point> region : regions) {
            if (region.size() < 100) continue;

            // 计算区域边界
            int minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE;
            int maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
            for (Point p : region) {
                minX = Math.min(minX, p.x);
                minY = Math.min(minY, p.y);
                maxX = Math.max(maxX, p.x);
                maxY = Math.max(maxY, p.y);
            }
            Rectangle rect = new Rectangle(
                    minX, minY,
                    maxX - minX + 1,
                    maxY - minY + 1
            );

            // 在左上角1/8区域
            if (rect.x < searchWidth && rect.y < searchHeight) {
                candidates.add(rect);
            }
        }

        if (candidates.isEmpty()) {
            throw new IOException("未找到符合条件的黑色定位块");
        }

        // 4. 选择最靠近左上角的矩形
        Rectangle selected = null;
        double minDistance = Double.MAX_VALUE;
        for (Rectangle rect : candidates) {
            double dist = rect.x * rect.x + rect.y * rect.y;
            if (dist < minDistance) {
                minDistance = dist;
                selected = rect;
            }
        }

        // 5. 转换为PDF坐标（左上角为原点）
        double scaleX = pageWidth / imgWidth;
        double scaleY = pageHeight / imgHeight;
        double blockX = selected.x * scaleX;
        double blockY = selected.y * scaleY;

        System.out.printf("黑色定位块坐标：x=%.2f, y=%.2f%n", blockX, blockY);
        return new double[]{blockX, blockY};
    }

    private static boolean isBlackPixel(BufferedImage image, int x, int y) {
        int rgb = image.getRGB(x, y);
        int r = (rgb >> 16) & 0xFF;
        int g = (rgb >> 8) & 0xFF;
        int b = rgb & 0xFF;
        return r <= 85 && g <= 85 && b <= 85;
    }

    // 修改后的findQuestions方法（增加startNumber参数）
    private static List<QuestionPosition> findQuestions(
            List<TextPosition> positions,
            double offset,
            int startNumber,
            double pageHeight,  // 新增参数
            String ctype
    ) {
        List<QuestionPosition> questions = new ArrayList<>();
        List<TextLine> textLines = groupTextLines(positions);

        int currentNumber = startNumber;  // 使用传入的起始编号
        // 遍历所有文本行，用于检测题目分界行
        for (int i = 0; i < textLines.size(); i++) {
            // 获取当前行的文本对象（包含文字内容和坐标信息）
            TextLine line = textLines.get(i);
            String lineTxt = line.getText();
            String oldType = ctype;
            if (lineTxt.contains("选择题")) ctype = "选择题";
            else if (lineTxt.contains("填空题")) ctype = "填空题";
            else if (lineTxt.contains("解答题")) ctype = "解答题";
            if (!oldType.equals(ctype)) {
                QuestionPosition qp = new QuestionPosition();
                qp.flag = false;
                qp.questionModel = ctype;
                qp.questionNumber = -1;
                questions.add(qp);
            }
            // 使用正则表达式匹配包含"本题 X 分"格式的文本行（X为任意数字）
            // 示例匹配文本："本题 10 分" 或 "本题5分"
            if (lineTxt.matches(".*本题\\s*\\d+\\s*分.*")) {
                // 使用正则表达式提取数字部分
                java.util.regex.Pattern pattern = java.util.regex.Pattern.compile("本题\\s*(\\d+)\\s*分");
                java.util.regex.Matcher matcher = pattern.matcher(lineTxt);

                // 计算当前题目区域的起始Y坐标（需减去偏移量调整位置）
                double startY = line.minY - offset;

                // 如果已有已记录的问题，则更新前一个问题的结束位置
                // 将当前起始位置设为前一个问题的结束位置（区间不重叠）
                if (!questions.isEmpty()) {
                    if (questions.get(questions.size() - 1).questionNumber == -1 && questions.size() > 2) {
                        questions.get(questions.size() - 2).endY = startY;
                    }
                    else {
                        questions.get(questions.size() - 1).endY = startY;
                    }
                }

                // 创建新的题目位置对象
                QuestionPosition qp = new QuestionPosition();
                qp.flag = true;
                if (matcher.find()) {
                    int x = Integer.parseInt(matcher.group(1));
                    qp.x = x;
                    // 这里可以使用变量x进行后续操作

                }
                // 分配全局递增的题目编号（currentNumber为外部计数器）
                qp.questionNumber = currentNumber++;
                // 记录当前题目的起始Y坐标
                qp.startY = startY;
                qp.questionModel = ctype;
                // 将新题目位置对象加入列表
                questions.add(qp);
            }
            // 新增逻辑：查找当前行中的$符号
            if (lineTxt.contains("$")) {
                for (TextPosition pos : line.positions) {
                    if ("$".equals(pos.getUnicode())) {
                        questions.get(questions.size() - 1).rX = pos.getX() + 5;
                        questions.get(questions.size() - 1).rY = pos.getY() - 13; // 转换为左上角坐标系
                        break; // 只取第一个匹配项
                    }
                }
            }

        }

        if (!questions.isEmpty()) {
            questions.get(questions.size() - 1).endY = 0;
        }

        return questions;
    }


    // 题目位置辅助类
    private static class QuestionPosition {
        public String questionModel;
        int questionNumber;
        double startY;
        double endY;
        int x; //分数
        double rX;
        double rY;
        boolean flag;//是否有效
    }

    // 文本行分组辅助类
    private static List<TextLine> groupTextLines(List<TextPosition> positions) {
        List<TextLine> lines = new ArrayList<>();
        TextLine currentLine = null;

        for (TextPosition pos : positions) {
            float y = pos.getY();
            String text = pos.getUnicode();

            if (currentLine == null || Math.abs(y - currentLine.baseY) > 2) {
                currentLine = new TextLine(y);
                lines.add(currentLine);
            }
            currentLine.addText(text, pos); // 传递整个TextPosition对象
        }
        return lines;
    }

    private static class TextLine {
        float baseY;
        float minY;
        float maxY;
        StringBuilder textBuilder = new StringBuilder();
        List<TextPosition> positions = new ArrayList<>(); // 新增positions列表

        TextLine(float baseY) {
            this.baseY = baseY;
            this.minY = baseY;
            this.maxY = baseY;
        }

        void addText(String text, TextPosition pos) { // 参数改为TextPosition
            textBuilder.append(text);
            positions.add(pos); // 保存TextPosition
            minY = Math.min(minY, pos.getY());
            maxY = Math.max(maxY, pos.getY());
        }

        String getText() {
            return textBuilder.toString().replaceAll("\\s+", "");
        }
    }
}
